package server;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import server.adapter.Adapter;
import server.adapter.CoyoteAdapter;
import server.classloader.WebAppClassloader;
import server.connector.Connector;
import server.connector.Endpoint;
import server.connector.ProtocolHandler;
import server.connector.impl.BioEndpoint;
import server.connector.impl.Http11ProtocolHandler;
import server.container.*;
import server.container.impl.*;

import java.io.*;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

/**
 * Minicat的主类
 */
public class Bootstrap {
    private Server server;

    /**
     * 实现webapps部署多个项目，并且加载
     */
    public void start(){
        init();
        this.server.start();
    }

    /**
     * 初始化
     */
    private void init(){
        //加载配置文件server.xml以及初始化Context容器和Wapper容器
        try {
            load();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        server.init();
    }

    private void load() throws FileNotFoundException {
        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("server.xml");
        SAXReader saxReader = new SAXReader();
        try {
            Document server = saxReader.read(resourceAsStream);
            Element rootElement = server.getRootElement();
            this.server = createServer();

            //初始化service
            List<Element> servicesList = rootElement.selectNodes("//Service");
            Service []services = new Service[servicesList.size()];
            for (int i = 0; i < servicesList.size(); i++) {
                services[i] = createService(this.server,servicesList.get(i));
            }
            this.server.setServices(services);
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }

    /**
     * 构建server
     * @return
     */
    private Server createServer() {
        return new StandServer();
    }

    /**
     * 创建Service节点
     * @param server
     * @param element
     * @return
     */
    private Service createService(Server server ,Element element) throws FileNotFoundException {
        List<Element> listConnector = element.selectNodes("//Connector");
        List<Element> listEngine = element.selectNodes("//Engine");
        Service service = new StandService();
        for (int i = 0; i < listEngine.size(); i++) {
            Engine engine = createEngine(service,listEngine.get(i));
            service.addEngine(engine);
        }
        service.setServer(server);

        for (int i = 0; i < listConnector.size(); i++) {
            Element elementConnector = listConnector.get(i);
            String port = elementConnector.attributeValue("port");
            Adapter adapter = new CoyoteAdapter();
            Endpoint endpoint = new BioEndpoint(adapter);
            ProtocolHandler protocolHandler = new Http11ProtocolHandler(endpoint);
            Connector connector = new Connector(protocolHandler);
            adapter.setConnector(connector);
            protocolHandler.setConnector(connector);
            endpoint.setProtocolHandler(protocolHandler);
            connector.setPort(Integer.valueOf(port));
            connector.setServer(server);
            connector.setService(service);

            server.addConnector(connector);
        }
        return service;
    }

    /**
     * 创建引擎
     * @param element
     * @return
     */
    private Engine createEngine(Service service,Element element) throws FileNotFoundException {
        List<Element> listHost = element.selectNodes("//Host");
        Engine engine = new StandEngine();
        Host[] hosts = new Host[listHost.size()];
        for (int i = 0; i < listHost.size(); i++) {
            hosts[i] = createHost(engine,listHost.get(i));
        }
        engine.setHosts(hosts);
        return engine;
    }

    /**
     * 创建Host容器
     * @param engine
     * @param element
     * @return
     */
    private Host createHost(Engine engine, Element element) throws FileNotFoundException {
        Host host = new StandHost();
        String name = element.attributeValue("name");
        String appBase = element.attributeValue("appBase");
        host.setName(name);
        host.setAppBase(appBase);
        host.setEngine(engine);

        File baseFile = new File(host.getAppBase());
        File[] files = baseFile.listFiles();
        for (int i = 0; i < files.length; i++) {
            File web = files[i];
            if ( web.isDirectory() ){
                // 初始化Context
                Context context = createContext(web);
                host.addContext(context);
            }
        }
        return host;
    }

    /**
     * 创建上下文容器
     * @param web
     * @return
     */
    private Context createContext(File web) throws FileNotFoundException {
        Context context = new StandContext();
        String name = web.getName();
        context.setContextName(name);
        //将class文件加载到类加载器中
        File classPath = new File(web,"/WEB-INF/classes");
        URL[] urls = new URL[1];
        try {
            urls[0] = classPath.toURI().toURL();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        context.setClassloader(new WebAppClassloader(urls));
        // 加载web.xml,并解析出Wapper
        File webXml = new File(web,"/WEB-INF/web.xml");
        if (webXml.exists()){
            createWapper(context,webXml);
        }
        return context;
    }

    private void createWapper(Context context, File webXml) throws FileNotFoundException {
        InputStream inputStream = new FileInputStream(webXml);
        // 1.获取解析器
        SAXReader saxReader = new SAXReader();
        try {
            // 2.获得document文档对象
            Document document = saxReader.read(inputStream);
            // 3.获取根元素
            Element rootElement = document.getRootElement();
            // 4.获取根元素下的子元素
            List<Element> childElements = rootElement.elements();

            //获取所有的url集合
            Map<String,String> urlMap = new HashMap<String,String>();
            // 5.遍历子元素

            for (Element element : childElements) {
                if ("servlet-mapping".equals(element.getName())) {
                    //获取servlet-name元素
                    Element servletName = element.element("servlet-name");
                    String servletNameText = servletName.getText();

                    //获取url-pattern元素
                    Element urlPattern = element.element("url-pattern");
                    String urlPatternText = urlPattern.getText();
                    urlMap.put(servletNameText,urlPatternText);
                }

            }
            for (Element element : childElements) {
                //6.判断元素名称为servlet的元素
                if ("servlet".equals(element.getName())) {
                    //7.获取servlet-name元素
                    Element servletName = element.element("servlet-name");
                    String servletNameText = servletName.getText();
                    System.out.println(servletNameText);
                    //8.获取servlet-class元素
                    Element servletClass = element.element("servlet-class");
                    String servletClassText = servletClass.getText();
                    System.out.println(servletClassText);

                    String urlPattern = urlMap.get(servletNameText);
                    System.out.println(urlPattern);
                    if(urlPattern!=null&&!"".equals(urlPattern)){
                        Wapper wapper = new StandWapper();
                        wapper.setServletName(servletNameText);
                        wapper.setClassName(servletClassText);
                        wapper.setUrlPattern(urlPattern);
                        wapper.setContext(context);
                        context.addWapper(wapper);
                    }
                }
            }

        }catch (DocumentException e) {
            e.printStackTrace();
        }
    }



    /**
     * Minicat 的程序启动入口
     * @param args
     */
    public static void main(String[] args) {
        new Bootstrap().start();
    }
}
